package com.kantboot.user.account.service.impl;

import com.kantboot.functional.verification.code.domain.dto.SendVerificationCodeDTO;
import com.kantboot.functional.verification.code.domain.enums.VerificationCodeTypeCodeEnum;
import com.kantboot.functional.verification.code.service.IFunctionalVerificationCodeService;
import com.kantboot.global.exception.GlobalException;
import com.kantboot.user.account.domain.dto.UserAccountRegisterDTO;
import com.kantboot.user.account.domain.dto.UserAccountSendVerificationCodeDTO;
import com.kantboot.user.account.domain.entity.UserAccount;
import com.kantboot.user.account.domain.enums.UserAccountVerificationCodeSceneCodeEnums;
import com.kantboot.user.account.domain.vo.LoginVO;
import com.kantboot.user.account.repostiroy.UserAccountRepository;
import com.kantboot.user.account.service.IUserAccountRegisterService;
import com.kantboot.user.account.service.IUserAccountService;
import com.kantboot.user.account.service.IUserAccountTokenService;
import com.kantboot.util.common.password.KantbootPassword;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class UserAccountRegisterServiceImpl implements IUserAccountRegisterService {

    @Resource
    private IUserAccountService userAccountService;

    @Resource
    private UserAccountRepository repository;

    @Resource
    private IUserAccountTokenService userAccountTokenService;

    @Resource
    private IFunctionalVerificationCodeService verificationCodeService;

    @Resource
    private KantbootPassword kantbootPassword;

    /**
     * 校验验证码
     */
    private void checkVerificationCode(SendVerificationCodeDTO sendVerificationCodeDTO, String verificationCode) {
        // 验证码校验
        Boolean verify = verificationCodeService.verify(sendVerificationCodeDTO, verificationCode);
        if (!verify) {
            // 提示验证码错误
            throw GlobalException.userAccount.VERIFICATION_CODE_ERROR;
        }
    }

    @Override
    public LoginVO registerByUsernameAndPassword(String username, String password) {
        // 查询用户名是否已存在
        UserAccount userAccountByUsername = repository.findByUsername(username);
        if (userAccountByUsername != null) {
            // 用户名已存在
            throw GlobalException.userAccount.USERNAME_EXIST;
        }
        UserAccount userAccountToSave = new UserAccount();
        userAccountToSave.setUsername(username);
        // 此处无需加密，在调用createUserAccount时会加密
        userAccountToSave.setPassword(password);
        // 创建用户账号
        UserAccount userAccount = userAccountService.createUserAccount(userAccountToSave);
        // 生成令牌
        String token = userAccountTokenService.generateToken(userAccount.getId());
        return new LoginVO()
                .setToken(token)
                .setUserAccount(userAccount);
    }

    @Override
    public void sendRegisterVerificationCode(UserAccountSendVerificationCodeDTO dto) {
        // 接受者
        String phone = dto.getTo();
        // 手机区号
        String phoneAreaCode = dto.getPhoneAreaCode();
        // 类型编码
        String typeCode = dto.getTypeCode();

        // 如果typeCode为邮箱
        if (VerificationCodeTypeCodeEnum.EMAIL.equals(typeCode)) {
            // 判断邮箱是否已存在
            UserAccount userAccountByEmail = repository.findByEmail(phone);
            if (userAccountByEmail != null) {
                // 邮箱已存在
                throw GlobalException.userAccount.EMAIL_EXIST;
            }
        }

        // 如果typeCode为短信
        if (VerificationCodeTypeCodeEnum.SMS.equals(typeCode)) {
            // 判断手机号是否已存在
            UserAccount userAccountByPhone = repository.findByPhoneAreaCodeAndPhone(phoneAreaCode, phone);
            if (userAccountByPhone != null) {
                // 手机号已存在
                throw GlobalException.userAccount.PHONE_EXIST;
            }
        }

        SendVerificationCodeDTO sendVerificationCodeDTO = new SendVerificationCodeDTO()
                .setPhoneAreaCode(phoneAreaCode)
                .setTo(phone)
                .setTypeCode(typeCode)
                .setSceneCode(UserAccountVerificationCodeSceneCodeEnums.REGISTER);
        verificationCodeService.send(sendVerificationCodeDTO);
    }

    @Override
    public LoginVO registerByPhoneAndVerificationCode(UserAccountRegisterDTO dto) {
        SendVerificationCodeDTO sendVerificationCodeDTO = new SendVerificationCodeDTO()
                .setPhoneAreaCode(dto.getPhoneAreaCode())
                .setTo(dto.getPhone())
                .setTypeCode(VerificationCodeTypeCodeEnum.SMS)
                .setSceneCode(UserAccountVerificationCodeSceneCodeEnums.REGISTER);

        // 校验验证码
        checkVerificationCode(sendVerificationCodeDTO, dto.getVerificationCode());

        UserAccount userAccountToSave = new UserAccount();
        userAccountToSave.setUsername(dto.getUsername());
        userAccountToSave.setPassword(dto.getPassword());
        userAccountToSave.setEmail(dto.getEmail());
        userAccountToSave.setPhoneAreaCode(dto.getPhoneAreaCode());
        userAccountToSave.setPhone(dto.getPhone());
        UserAccount userAccount = userAccountService.createUserAccount(userAccountToSave);
        String token = userAccountTokenService.generateToken(userAccount.getId());

        return new LoginVO()
                .setToken(token)
                .setUserAccount(userAccount);
    }

    @Override
    public LoginVO registerByEmailAndVerificationCode(UserAccountRegisterDTO dto) {
        SendVerificationCodeDTO sendVerificationCodeDTO = new SendVerificationCodeDTO()
                .setTo(dto.getEmail())
                .setTypeCode(VerificationCodeTypeCodeEnum.EMAIL)
                .setSceneCode(UserAccountVerificationCodeSceneCodeEnums.REGISTER);
        String verificationCode = dto.getVerificationCode();

        // 校验验证码
        checkVerificationCode(sendVerificationCodeDTO, verificationCode);

        UserAccount userAccountToSave = new UserAccount();
        userAccountToSave.setUsername(dto.getUsername());
        userAccountToSave.setPassword(dto.getPassword());
        userAccountToSave.setEmail(dto.getEmail());
        userAccountToSave.setPhoneAreaCode(dto.getPhoneAreaCode());
        userAccountToSave.setPhone(dto.getPhone());
        UserAccount userAccount = userAccountService.createUserAccount(userAccountToSave);

        String token = userAccountTokenService.generateToken(userAccount.getId());
        return new LoginVO()
                .setToken(token)
                .setUserAccount(userAccount);
    }
}
